use anyhow::Result;
use serde::{Deserialize, Serialize};
use serde_json;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

#[derive(Deserialize, Serialize)]
pub struct Server {
    #[serde(default)]
    disabled: bool,
    #[serde(default)]
    timeout: Option<u32>,
    #[serde(default)]
    command: String,
    #[serde(default)]
    args: Vec<String>,
    #[serde(rename = "type")]
    pub server_type: String,
    #[serde(default)]
    url: String,
    #[serde(default)]
    pub cwd: Option<PathBuf>
}

impl Server {
    pub fn to_string(&self) -> String {
        serde_json::to_string(self).unwrap_or_default()
    }

    pub fn is_disabled(&self) -> bool {
        self.disabled
    }

    pub fn get_url(&self) -> String {
        self.url.clone()
    }

    pub fn get_server_type(&self) -> String {
        if self.server_type == "stdio" {
            return "stdio".to_string();
        }
        if self.server_type == "sse" {
            return "sse".to_string();
        }
        panic!("unknown server type {}", self.server_type);
    }

    pub fn get_command(&self)  -> String {
        if cfg!(target_os = "windows") 
        {
            return "cmd".to_string();
        }
        return self.command.clone();
    }

    pub fn get_args(&self)  -> Vec<String> {
        let mut args = Vec::new();
        if cfg!(target_os = "windows") 
        {
            args.reserve(self.args.len() + 2);
            args.push("/k".to_string());
            args.push(self.command.clone());
            args.extend_from_slice(self.args.as_slice());
        } else {
            args = self.args.clone();
        }
        return args;
    }

    pub fn get_timeout(&self)  -> u32 {
        match self.timeout {
            Some(timeout) => timeout,
            None => 60,
        }
    }
}

#[derive(Deserialize)]
pub struct ParamConfig {
    pub host: String,
    pub port: u32,
    #[serde(rename = "mcpServers")]
    pub mcp_servers: HashMap<String, Server>,
}

impl ParamConfig {
    pub fn load(path: PathBuf) -> Result<Self, Box<dyn std::error::Error>> {
        let mut file = File::open(path)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        let config: Self = serde_json::from_str(&contents)?;
        Ok(config)
    }
}
